package com.ranyk.www.config;


import com.ranyk.www.common.security.RetryLimitHashedCredentialsMatcher;
import com.ranyk.www.common.security.SystemAuthorizingRealm;
import net.sf.ehcache.CacheManager;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * CLASS_NAME: ShiroConfig.java <br/>
 *
 * @author ranyk           <br/>
 * @version V1.0           <br/>
 * @decription: Shiro 配置  <br/>
 * @date: 2022-04-14 <br/>
 */
@Configuration
public class ShiroConfig {

    /**
     * 配置 {@link WebSecurityManager} bean 对象
     *
     * @param shiroDbRealm        传入 {@link Realm} bean 对象
     * @param shiroEhcacheManager 传入 {@link EhCacheManager} bean 对象
     * @param rememberMeManager   传入 {@link RememberMeManager} bean 对象
     * @return 返回配置好的 {@link WebSecurityManager} bean 对象
     */
    @Bean
    public WebSecurityManager securityManager(@Qualifier("shiroDbRealm") Realm shiroDbRealm,
                                              @Qualifier("shiroEhcacheManager") EhCacheManager shiroEhcacheManager,
                                              @Qualifier("rememberMeManager") RememberMeManager rememberMeManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroDbRealm);
        securityManager.setCacheManager(shiroEhcacheManager);
        securityManager.setRememberMeManager(rememberMeManager);
        return securityManager;
    }

    /**
     * 配置 {@link Realm} bean 对象
     *
     * @param hashedCredentialsMatcher 传入 {@link CredentialsMatcher} bean 对象
     * @return 返回配置好的  {@link Realm} bean 对象
     */
    @Bean
    public Realm shiroDbRealm(@Qualifier("hashedCredentialsMatcher") CredentialsMatcher hashedCredentialsMatcher) {
        SystemAuthorizingRealm realm = new SystemAuthorizingRealm();
        realm.setCredentialsMatcher(hashedCredentialsMatcher);
        return realm;
    }

    /**
     * 配置 {@link Cookie} bean 对象
     *
     * @return 返回配置好的 {@link Cookie} bean 对象
     */
    @Bean
    public Cookie rememberMeCookie() {
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(7 * 24 * 60 * 60);
        return cookie;
    }

    /**
     * 配置 {@link RememberMeManager} bean 对象
     *
     * @param rememberMeCookie 传入 {@link Cookie} bean 对象
     * @return 返回配置好的 {@link RememberMeManager} bean 对象
     */
    @Bean
    public RememberMeManager rememberMeManager(@Qualifier("rememberMeCookie") Cookie rememberMeCookie) {
        CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
        rememberMeManager.setCipherKey(Base64.decode("U3ByaW5nQmxhZGUAAAAAAA=="));
        rememberMeManager.setCookie(rememberMeCookie);
        return rememberMeManager;
    }


    /**
     * 配置 {@link ShiroFilterFactoryBean} bean 对象
     *
     * @param securityManager 传入 {@link WebSecurityManager} bean 对象
     * @return 返回配置好的 {@link ShiroFilterFactoryBean} bean 对象
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") WebSecurityManager securityManager) {
        Map<String, String> filterChainDefinitionMap = new HashMap<>(16);
        // 放行Swagger相关访问
        filterChainDefinitionMap.put("/swagger-ui/index.html", "anon");
        filterChainDefinitionMap.put("/swagger-ui/**", "anon");
        filterChainDefinitionMap.put("/webjars/springfox-swagger-ui/**", "anon");
        filterChainDefinitionMap.put("/swagger-resources/**", "anon");
        filterChainDefinitionMap.put("/v2/**", "anon");
        filterChainDefinitionMap.put("/v3/**", "anon");
        // 放行静态资源
        filterChainDefinitionMap.put("/static/**", "anon");
        // 放行公共资源
        filterChainDefinitionMap.put("/common/**", "anon");
        // 放行验证码请求
        filterChainDefinitionMap.put("/captcha-image", "anon");
        // 放行验证码
        filterChainDefinitionMap.put("/captcha-image.jpg", "anon");
        // 放行登录请求
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/**", "authc");
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        shiroFilter.setLoginUrl("/login");
        shiroFilter.setSuccessUrl("/index");
        shiroFilter.setUnauthorizedUrl("/isAuthenticated");
        shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilter;
    }

     /**
     * 配置 {@link AuthorizationAttributeSourceAdvisor} bean 对象
     *
     * @param securityManager 传入 {@link WebSecurityManager} bean 对象
     * @return 返回配置好的 {@link AuthorizationAttributeSourceAdvisor} bean 对象
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") WebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 配置 EhCacheManager bean 对象
     *
     * @param ehcache 传入 {@link CacheManager} bean 对象
     * @return 返回配置好的 {@link EhCacheManager} bean 对象
     */
    @Bean
    public EhCacheManager shiroEhcacheManager(@Qualifier("ehcache") CacheManager ehcache) {
        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManager(ehcache);
        return ehCacheManager;
    }

    /**
     * 配置 MethodInvokingFactoryBean bean
     *
     * @param securityManager 传入 {@link WebSecurityManager} bean 对象
     * @return 返回配置好参数的 {@link MethodInvokingFactoryBean} bean 对象
     */
    @Bean
    public MethodInvokingFactoryBean methodInvokingFactoryBean(@Qualifier("securityManager") WebSecurityManager securityManager) {
        MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean();
        factoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
        factoryBean.setArguments(securityManager);
        return factoryBean;
    }

    /**
     * 配置 CredentialsMatcher bean
     *
     * @param shiroEhcacheManager 传入 {@link EhCacheManager} bean 对象
     * @return 返回设置好参数的 {@link CredentialsMatcher}  bean 对象
     */
    @Bean
    public CredentialsMatcher hashedCredentialsMatcher(@Qualifier("shiroEhcacheManager") EhCacheManager shiroEhcacheManager) {
        RetryLimitHashedCredentialsMatcher hashedCredentialsMatcher = new RetryLimitHashedCredentialsMatcher(shiroEhcacheManager);
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        hashedCredentialsMatcher.setHashIterations(6);
        return hashedCredentialsMatcher;
    }

    /**
     * 配置 LifecycleBeanPostProcessor
     *
     * @return 返回 {@link LifecycleBeanPostProcessor} 对象
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

}
